#include <stdio.h>
#include <string.h>
#include "config.h"
//#include "key.h"
#include "sy8801.h"
#include "earbud_cmd.h"
#include <stdbool.h>
#include "msg.h"
#include "i2c.h"
#include "led.h"
#include "sw_timer.h"


#define HEADEST_L	0
#define HEADEST_R	1
#define MSG_EARR_OUT 3
#define MSG_EARL_OUT 4



uint8_t sy880x_heartbeat_timer = 0xff;

sy8801_struct_t sy8801;


void sy880x_write_reg(uint8_t reg, uint8_t dat)
{
	i2c2_write(APP_SY8801_IIC_READ_ADDR, reg, &dat, 1);
}

uint8_t sy880x_read_reg(uint8_t reg_address)
{
	uint8_t data;
	i2c2_read(APP_SY8801_IIC_READ_ADDR, reg_address, &data, 1);
	return data;
}

/*************************************************
  Copyright (C), 2019-2029, ATX Technology Co., Ltd.
  File name:      box_close_mode.c
  Author: bsy     Version: v1.0       Date: 20200811
  Description:    8801 unlock
  Others:         none
*************************************************/
void sy880x_unlock_reg(void)
{
	sy880x_write_reg(0x72,0x97);
    sy880x_write_reg(0x73,0x39);
}

/*************************************************
  Copyright (C), 2019-2029, ATX Technology Co., Ltd.
  File name:      box_close_mode.c
  Author: bsy     Version: v1.0       Date: 20200811
  Description:    8801 lock
  Others:         none
*************************************************/
void sy880x_lock_reg(void)
{
    sy880x_write_reg(0x72,0x00);
    sy880x_write_reg(0x73,0x00);
}

/*************************************************
  Copyright (C), 2019-2029, ATX Technology Co., Ltd.
  File name:      box_close_mode.c
  Author: bsy     Version: v1.0       Date: 20200811
  Description:    8801 read
  Others:         Check whether 8801 is powered on and initialized
*************************************************/
uint8_t get_sy800x_is_ready(void)
{
	if (sy880x_read_reg(ADDR_sy8801_ST_INIT) & 0x01)
		return 1;
    return 0;
}

/*************************************************
  Copyright (C), 2019-2029, ATX Technology Co., Ltd.
  File name:      box_close_mode.c
  Author: bsy     Version: v1.0       Date: 20200811
  Description:    none
  Others:         none
*************************************************/
void sy880x_init(void)
{
    uint8_t out_count = 0;
    
	memset(&sy8801,RESET,sizeof(sy8801));
	
    BOX_LOG("sy8801 init start\r\n");
    while (!get_sy800x_is_ready())
    {
        if(++out_count > 10)
        {
            BOX_LOG("sy8801 err\r\n");
            sy8801.init = DISABLE;
            return;
        }
        HAL_Delay(100);
    }
    sy8801.init = ENABLE;
    BOX_LOG("sy8801 init succeed\r\n");
    
    //protect release
    sy880x_unlock_reg();
    sy880x_write_reg(ADDR_sy8801_CONF_P06, 0x00);       //set battery voltage to 4.2V; Vsys = 5V
    sy880x_write_reg(ADDR_sy8801_CONF_P20, 0xC0 + 0x10 + 0x00);       //4.7V Adaptor adaptation voltage;  0.5mA led current
    sy880x_write_reg(ADDR_sy8801_CONF_P21, 0x00);       //communication driver: 100k
    sy880x_write_reg(ADDR_sy8801_CONF_P40, 0x00);       //battery low voltage: 3.1V
    sy880x_write_reg(ADDR_sy8801_CONF_P41, 0x04);       //battery voltage low warning: 3.4V
    sy880x_write_reg(ADDR_sy8801_CONF_P42, 0x00);       //
    sy880x_write_reg(ADDR_sy8801_CONF_P43, 0x00);       //
    sy880x_write_reg(ADDR_sy8801_CONF_P45, (0xA0 + 0x14 + 0x01)); //150mA + 2uA + 2uA
    sy880x_write_reg(ADDR_sy8801_CONF_P46, 0x00);       
    sy880x_write_reg(ADDR_sy8801_CTRL_COMIN, 0x00);       //close communication
    sy880x_write_reg(ADDR_sy8801_CTRL_OUT, 0x02);       //open boost; close output both left and right
    sy880x_write_reg(ADDR_sy8801_CTRL_LED, 0x01);       //LED use I2C; and all off

    BOX_LOG("SY8801_ST_ERR: %02X\r\n", sy880x_read_reg(ADDR_sy8801_ST_ERR));
    BOX_LOG("SY8801_ST_LOAD: %02X\r\n", sy880x_read_reg(ADDR_sy8801_ST_LOAD));
    BOX_LOG("SY8801_CTRL_OUT: %02X\r\n", sy880x_read_reg(ADDR_sy8801_CTRL_OUT));

    app_sy880x_heartbeat_timer_start();
}

void app_sy880x_heartbeat_timer_start(void)
{
    app_sy880x_heartbeat_timer_stop();
    sy880x_heartbeat_timer = sw_timer_start(500, 1, app_sy880x_heartbeat_handle);
}

void app_sy880x_heartbeat_timer_stop(void)
{
    if(sy880x_heartbeat_timer != 0xff)
        sy880x_heartbeat_timer = sw_timer_stop(sy880x_heartbeat_timer);
}

void app_sy880x_heartbeat_handle(void)
{
    app_sy880x_state_handle();
}


void app_sy880x_state_handle(void)
{
	uint8_t new_err, new_load;

	new_err = sy880x_read_reg(ADDR_sy8801_ST_ERR);
	new_load = sy880x_read_reg(ADDR_sy8801_ST_LOAD);
	sy8801.bat_reg = sy880x_read_reg(ADDR_sy8801_ST_BAT);
	
    //BOX_LOG("SY8801_ST_ERR: old:%02X, new:%02X\r\n", sy8801.err, new_err);
    //BOX_LOG("SY8801_ST_LOAD: old:%02X, new:%02X\r\n", sy8801.load,new_load);
    //BOX_LOG("SY8801_ST_BAT: %02X\r\n", sy8801.bat);

    sy8801_check_abnormal();
    sy8801_check_usb_state(new_err);
    sy8801_check_ear_state(new_load);
}


void sy8801_ear_5v_output_enable(uint8_t role)
{
    uint8_t reg = sy880x_read_reg(ADDR_sy8801_CTRL_OUT);
    
    if(role & (1<<EAR_L))
    {
        reg |= 0x04;
        sy8801.out |= (1<<EAR_L);
    }

    if(role & (1<<EAR_R))
    {
        reg |= 0x08;
        sy8801.out |= (1<<EAR_R);
    }
    
    sy880x_write_reg(ADDR_sy8801_CTRL_OUT, reg);
}


void sy8801_ear_5v_output_disable(uint8_t role)
{
    uint8_t reg = sy880x_read_reg(ADDR_sy8801_CTRL_OUT);
    
    if(role & (1<<EAR_L))
    {
        reg &= (~0x04);
        sy8801.out &= ~(1<<EAR_L);
    }
    
    if(role & (1<<EAR_R))
    {
        reg &= (~0x08);
        sy8801.out &= ~(1<<EAR_R);
    }
    
    sy880x_write_reg(ADDR_sy8801_CTRL_OUT, reg);
}


void sy8801_auto_detect_enable(void)
{
    uint8_t reg = sy880x_read_reg(ADDR_sy8801_CONF_P40);
    
    reg &= (~0x40);
    sy880x_write_reg(ADDR_sy8801_CONF_P40, reg);
}


void sy8801_auto_detect_disable(void)
{
    uint8_t reg = sy880x_read_reg(ADDR_sy8801_CONF_P40);
    
    reg |= 0x40;
    sy880x_write_reg(ADDR_sy8801_CONF_P40, reg);
}


void app_sy880x_enter_sleep(void)
{
    uint8_t temp = 0x01;//sy880x_read_reg(ADDR_sy8801_CTRL_OUT);
    sy880x_write_reg(ADDR_sy8801_CTRL_OUT, temp);
}


#if (SUPPORT_SY8801_LED)
void app_sy880x_set_led(uint8_t level)
{
    level = (level << 1) | 0x01;
    sy880x_write_reg(ADDR_sy8801_CTRL_LED, level);
}
#endif


void sy8801_check_abnormal(void)
{
    if(sy8801.err & BIT(BIT_sy8801_ST_ERR_INTERNAL))
    {
        BOX_LOG("chip abnormal\n");
        app_msg_send(MSG_SY880X_ABNORMAL);
    }
    
    if(sy8801.err & BIT(BIT_sy8801_ST_ERR_HIGH_L))
	{
		uint8_t state = EAR_L;
	    app_msg_send_with_param(MSG_SY880X_EAR_ABNORMAL, &state, 1);
	}
    
    if(sy8801.err & BIT(BIT_sy8801_ST_ERR_HIGH_R))
	{
		uint8_t state = EAR_R;
	    app_msg_send_with_param(MSG_SY880X_EAR_ABNORMAL, &state, 1);
	}
}


void sy8801_check_usb_state(uint8_t new_err)
{
    // usb state
	if(sy8801.err != new_err)
	{
	    if(!(sy8801.err & 0x10) && (new_err & 0x10))
			app_msg_send(MSG_USB_IN);
		else if((sy8801.err & 0x10) && !(new_err & 0x10))
			app_msg_send(MSG_USB_OUT);
        
		if(!(sy8801.err & 0x20) && (new_err & 0x20))
			app_msg_send(MSG_BAT_CHARGE);
		else if((sy8801.err & 0x20) && !(new_err & 0x20))
			app_msg_send(MSG_BAT_CHARGE_STOP);
		
		if(!(sy8801.err & 0x40) && (new_err & 0x40))
			app_msg_send(MSG_BAT_CHARGE_FULL);  //charge full

        BOX_LOG("SY8801_ST_ERR: old:%02X, new:%02X\r\n", sy8801.err, new_err);
        sy8801.err = new_err;
	}
}


void sy8801_check_ear_state(uint8_t new_load)
{
    uint8_t state;
    
    //ear
	if(sy8801.load != new_load)
	{
//////////3.3V out state
        if(!(sy8801.out & (1<<EAR_L)))
        {
    		if(!(sy8801.load & 0x04) && (new_load & 0x04))
    		{
    			//L in box
    			state = EAR_L;
    			app_msg_send_with_param(MSG_EAR_IN_BOX, &state, 1);
    		}
    		else if((sy8801.load & 0x04) && !(new_load & 0x04))
    		{
    			//L out box
    			state = EAR_L;
    			app_msg_send_with_param(MSG_EAR_OUT_BOX, &state, 1);
    		}
        }

        if(!(sy8801.out & (1<<EAR_R)))
        {
    		if(!(sy8801.load & 0x08) && (new_load & 0x08))
    		{
    			//R in box
    			state = EAR_R;
    			app_msg_send_with_param(MSG_EAR_IN_BOX, &state, 1);
    		}
    		else if((sy8801.load & 0x08) && !(new_load & 0x08))
    		{
    			//R out box
    			state = EAR_R;
    			app_msg_send_with_param(MSG_EAR_OUT_BOX, &state, 1);
    		}
        }
        
//////////5V out state
        if(sy8801.out & (1<<EAR_L))
        {
            if(!(sy8801.load & 0x10) && (new_load & 0x10))
    		{
    			//L out box
    			state = EAR_L;
    			app_msg_send_with_param(MSG_EAR_OUT_BOX, &state, 1);
    		}
        }

        if(sy8801.out & (1<<EAR_R))
        {
            if(!(sy8801.load & 0x20) && (new_load & 0x20))
    		{
    			//R out box
    			state = EAR_R;
    			app_msg_send_with_param(MSG_EAR_OUT_BOX, &state, 1);
    		}
        }
        
        BOX_LOG("SY8801_ST_LOAD: old:%02X, new:%02X, out:%02X\r\n", sy8801.load, new_load, sy8801.out);
        sy8801.load = new_load;
	}
}


uint16_t app_get_sy8801_battery(void)
{
	uint16_t sy8801_bat = 2700;
	sy8801_bat += (((sy8801.bat_reg >> 1) & 0x1f) * 50);
	return sy8801_bat;
}



///////////////////end//////////////////////////

